#ifndef CONTROL_H
#define CONTROL_H

/*
 * Pliki nagłówkowe biblioteki
 */
#include "handdetector.h"
#include "handgestureexception.h"
#include "handtracker.h"
#include "skindetector.h"
#include "trajectory.h"
#include "dynamicgesture.h"
#include "staticgesture.h"

#include "gestureobserver.h"

#include <vector>
#include <string>

#include <cv.h>
#include <highgui.h>

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>

using namespace cv;
using namespace std;

namespace mlgesture {

class Control
{
public:
	Control(int video_id = -1, int hands_num = 1) throw(HandGestureException);
	~Control();

	void getFrame(Mat &frame, vector<Rect> *hands = NULL) throw(HandGestureException);
	void getMask(Mat &mask) const throw(HandGestureException);
	Size getFrameSize() const;
	void setHandsNum(const int num) throw(HandGestureException);
	void adjustSkinFilter(const int lower_threshold, const int upper_threshold,
						  const int lower_value_threshold, const int upper_value_threshold) throw (HandGestureException);
	void setAdaptiveAlgoritm(const bool adapt);
	void adjustTrackingSensity(const double sensity) throw (HandGestureException);
	const vector<Mat>& getTrackShapeMask() throw (HandGestureException);
	void releaseCamera();

	void enableTrajectory(bool enable);
	void enableDynamicGesture(bool enable) throw (HandGestureException);
	void enableStaticGesture(bool enable);
	const vector<Trajectory>& getTrajectory(vector<bool>& trajectory_status, vector<bool>& trajectory_end) const throw (HandGestureException);
	const vector<int>& getLastDirection() const throw (HandGestureException);
	const vector<Point>& getLastPos() const throw (HandGestureException);

	void loadDynamicGestureModels(const vector<QString> &model_files, const QString &garbage_file) throw (HandGestureException);
	void loadStaticGesturesModels(const QString &model_file, const QString &scale_factors_file, const QString &labels_file) throw (HandGestureException);

	boost::thread startThread();
	void operator()();
	void stopProcess();
	bool isFrame_;

private:
	class ControlThread {
	public:
		ControlThread(Control *control);
		void operator()();

	private:
		Control *control_;
	};

	bool process();
	void clean();
	void createIntersactionTable(int hands_num);
	void deleteIntersactionTable();
	void processTrajectory() throw (HandGestureException);
	void captureHandsShape();
	void checkIntersactions() throw (HandLostException);

	VideoCapture cap_;
	bool isHand_;
	volatile bool isRunning_;
	SkinDetector *skinFilter_;
	HandDetector *handDetector_;
	vector<HandTracker*> handTrackers_;
	Size frameSize_;
	int handsNum_;
	int camId_;
	double trackingSensity_;
	int** intersactions_;

	Mat frame_;
	Mat bitMask_;
	Mat hsv_;
	Mat bitMaskBGR_;
	vector<Rect> handsRect_;
	Rect handRectL_;
	Rect handRectR_;
	vector<Mat> hsvChannels_;
	vector<Mat> rgbChannels_;
	vector<Mat> trackShapes_;
	float handsAngle_;
	float handsDistance_;
	vector<Point> centers_;
	const int skinMorphingMethod_;

	bool staticGestureActive_;
	bool dynamicGestureActive_;
	bool trajectoryActive_;
	vector<bool> trajectoryEnd_;
	vector<int> lastDirection_;
	vector<Trajectory> trajectory_;

	vector<Point> lastPos_;
	vector<bool> trackingState_;
	Trajectory actTrack_;

	DynamicGesture *dynamic_;
	void processDynamicGestures() throw (HandGestureException);
	vector<QString> dynamicModelFiles_;
	QString dynamicGarnageFile_;

	StaticGesture *static_;
	QString staticModelFile_;
	QString staticScaleFactorsFile_;
	QString staticLabelsFile_;
	void proccessStaticGestures() throw (HandGestureException);

	boost::mutex frameMutex_;
	boost::mutex isRunningMutex_;
	boost::mutex staticImageMutex_;

	bool isError_;
	std::string errorMsg_;
};

}

#endif // CONTROL_H
